package smetana.util;

import org.apache.pivot.wtk.ApplicationContext;

/**
 * Will run pushed works one by one.
 * Only 1 work is performed at time.
 * If work A is running and B is already waiting for work A it in queue
 * and we are adding work C, then work B will be removed (fogot) and
 * work C will be pushed into queue right after A. So in this case
 * C will override B and B will never be performed.
 * 
 * @author dmitry.mamonov
 */
public abstract class StrangeQueue {
    private boolean running = false;

    private Work pendingWork = null;

    protected abstract void onActivityChange(boolean active);

    public void push(final Work work) {
        ApplicationContext.queueCallback(new Runnable() {
            @Override
            public void run() {
                if (running == false) {
                    pendingWork = work;
                    runWork();
                } else {
                    pendingWork = work;
                }
            }
        });
    }

    private void runWork() {
        if (pendingWork == null) {
            if (running == true) {
                running = false;
                onActivityChange(false);
            }
        } else {
            if (running == false) {
                running = true;
                onActivityChange(true);
            }
            final Work work = pendingWork;
            pendingWork = null;
            new Thread() {
                @Override
                public void run() {
                    try {
                        work.doWork();
                    } catch (final Throwable th) {
                        ApplicationContext.queueCallback(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    work.failed(th);
                                } catch (Throwable th) {
                                    //TODO I prefer to manage this exception through application context.
                                    th.printStackTrace();
                                }
                            }
                        });
                    } finally {
                        ApplicationContext.queueCallback(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    work.publishResults();
                                } catch (Throwable th) {
                                    //TODO I prefer to manage this exception through application context.
                                    th.printStackTrace();
                                }
                            }
                        });
                    }
                    runWork();
                }
            }.start();
        }
    }

}
